RFCに準拠したHTTPヘッダ比較について


概要

RFCに反してるライブラリ使ってハマってた。



何が起こったか

httpのヘッダのキーに大文字小文字でフル一致できる文字列が入っているはず、という

謎の期待をするクライアント実装があって、

それを知らずに使っていたため通信結果が失敗に終わるという感じで、なかなか真相に気づかずにハマった。


対象のライブラリはこちら。


websocket-sharp

https://github.com/sta/websocket-sharp



困ってた部分のコードはこんな感じになっている。


WebSocket.cs

https://github.com/sta/websocket-sharp/blob/ad563fa46c688094048fe3ed7a1df292e7bbe5d3/websocket-sharp/WebSocket.cs#L779

      var headers = response.Headers;

      if (!validateSecWebSocketAcceptHeader (headers["Sec-WebSocket-Accept"])) {

        message = "Includes no Sec-WebSocket-Accept header, or it has an invalid value.";

        return false;

      }


      if (!validateSecWebSocketProtocolServerHeader (headers["Sec-WebSocket-Protocol"])) {

        message = "Includes no Sec-WebSocket-Protocol header, or it has an invalid value.";

        return false;

      }


      if (!validateSecWebSocketExtensionsServerHeader (headers["Sec-WebSocket-Extensions"])) {

        message = "Includes an invalid Sec-WebSocket-Extensions header.";

        return false;

      }


      if (!validateSecWebSocketVersionServerHeader (headers["Sec-WebSocket-Version"])) {

        message = "Includes an invalid Sec-WebSocket-Version header.";

        return false;

      }


この内容と大文字小文字がジャストマッチしてないと、WebSocket接続のハンドシェイクが失敗に終わる。



対して、WebSocketのRFCの基準はこちら

https://tools.ietf.org/html/rfc6455#section-2.1


Comparing two strings in an _ASCII case-insensitive_ manner means

   comparing them exactly, code point for code point, except that the

   characters in the range U+0041 to U+005A (i.e., LATIN CAPITAL LETTER

   A to LATIN CAPITAL LETTER Z) and the corresponding characters in the

   range U+0061 to U+007A (i.e., LATIN SMALL LETTER A to LATIN SMALL

   LETTER Z) are considered to also match.


文字列比較について、特に_ASCII case-insensitive_って書いてあるところはこうすべきだよ~みたいな但し書きがあって、

・大文字だろうが小文字だろうがマッチすること

という感じになっている。



というわけで、修正したものをプルリク済み。

https://github.com/sta/websocket-sharp/pull/315



ちなみに一切テストコードが存在しないんで、まあ、なんだ、、一度手元で動かしたけど確証はないので、つらい。